<template>
  <div class="app-container">
    <header>
      <h1 class="main-title">虚开增值税发票检测系统</h1>
    </header>
    <main class="content">
      <div class="container">
        <el-row :gutter="20">
          <!-- 发票图片上传 -->
          <el-col :span="12" :md="6">
            <div class="upload-container">
              <el-upload
                v-model:file-list="invoiceImg"
                list-type="picture-card"
                :limit="1"
                accept="image/*"
                :auto-upload="false"
                :on-change="(file, fileList) => handleFileChange(fileList, 'invoice')"
                :on-remove="(file, fileList) => handleFileRemove(file, fileList, 'invoice')"
                :on-preview="(file) => handlePreview(file, 'invoice')"
                :on-exceed="(files, fileList) => handleExceed(files, fileList, 'invoice')"
                :disabled="isInvoiceLoading"
                v-if="!ocrResults.invoice"
              >
                <div class="upload-icon">
                  <el-icon><Plus /></el-icon>
                  <div>发票图片</div>
                </div>
              </el-upload>
              
              <!-- AI识别中状态 -->
              <div v-if="isInvoiceLoading" class="ai-loading-container">
                <div class="ai-loading-content">
                  <el-icon class="ai-loading-icon"><Loading /></el-icon>
                  <div class="ai-loading-text">AI大模型正在识别中...</div>
                  <div class="ai-loading-subtext">请稍候，正在分析发票信息</div>
                </div>
              </div>
              
              <!-- 识别完成状态 -->
              <div v-else-if="ocrResults.invoice" class="recognition-complete">
                <div class="complete-icon">
                  <el-icon><CheckCircle /></el-icon>
                </div>
                <div class="complete-text">识别完成</div>
                <el-button type="primary" @click="viewDetails('invoice')" size="small" class="view-details-btn">
                  <el-icon><Document /></el-icon>
                  查看识别详情
                </el-button>
                <el-button type="info" @click="handlePreview(invoiceImg[0], 'invoice')" size="small" class="preview-btn">
                  预览图片
                </el-button>
                <el-button type="danger" @click="handleFileRemove(null, [], 'invoice')" size="small" class="remove-btn">
                  重新上传
                </el-button>
              </div>
            </div>
          </el-col>

          <!-- 合同图片上传 -->
          <el-col :span="12" :md="6">
            <div class="upload-container">
              <el-upload
                v-model:file-list="contractImg"
                list-type="picture-card"
                :limit="1"
                accept="image/*"
                :auto-upload="false"
                :on-change="(file, fileList) => handleFileChange(fileList, 'contract')"
                :on-remove="(file, fileList) => handleFileRemove(file, fileList, 'contract')"
                :on-preview="(file) => handlePreview(file, 'contract')"
                :on-exceed="(files, fileList) => handleExceed(files, fileList, 'contract')"
                :disabled="isContractLoading"
                v-if="!ocrResults.contract"
              >
                <div class="upload-icon">
                  <el-icon><Plus /></el-icon>
                  <div>合同图片</div>
                </div>
              </el-upload>
              
              <!-- AI识别中状态 -->
              <div v-if="isContractLoading" class="ai-loading-container">
                <div class="ai-loading-content">
                  <el-icon class="ai-loading-icon"><Loading /></el-icon>
                  <div class="ai-loading-text">AI大模型正在识别中...</div>
                  <div class="ai-loading-subtext">请稍候，正在分析合同信息</div>
                </div>
              </div>
              
              <!-- 识别完成状态 -->
              <div v-else-if="ocrResults.contract" class="recognition-complete">
                <div class="complete-icon">
                  <el-icon><CheckCircle /></el-icon>
                </div>
                <div class="complete-text">识别完成</div>
                <el-button type="primary" @click="viewDetails('contract')" size="small" class="view-details-btn">
                  <el-icon><Document /></el-icon>
                  查看识别详情
                </el-button>
                <el-button type="info" @click="handlePreview(contractImg[0], 'contract')" size="small" class="preview-btn">
                  预览图片
                </el-button>
                <el-button type="danger" @click="handleFileRemove(null, [], 'contract')" size="small" class="remove-btn">
                  重新上传
                </el-button>
              </div>
            </div>
          </el-col>

          <!-- 付款单据上传 -->
          <el-col :span="12" :md="6">
            <div class="upload-container">
              <el-upload
                v-model:file-list="paymentImg"
                list-type="picture-card"
                :limit="1"
                accept="image/*"
                :auto-upload="false"
                :on-change="(file, fileList) => handleFileChange(fileList, 'payment')"
                :on-remove="(file, fileList) => handleFileRemove(file, fileList, 'payment')"
                :on-preview="(file) => handlePreview(file, 'payment')"
                :on-exceed="(files, fileList) => handleExceed(files, fileList, 'payment')"
                :disabled="isPaymentLoading"
                v-if="!ocrResults.payment"
              >
                <div class="upload-icon">
                  <el-icon><Plus /></el-icon>
                  <div>付款单据</div>
                </div>
              </el-upload>
              
              <!-- AI识别中状态 -->
              <div v-if="isPaymentLoading" class="ai-loading-container">
                <div class="ai-loading-content">
                  <el-icon class="ai-loading-icon"><Loading /></el-icon>
                  <div class="ai-loading-text">AI大模型正在识别中...</div>
                  <div class="ai-loading-subtext">请稍候，正在分析付款单据信息</div>
                </div>
              </div>
              
              <!-- 识别完成状态 -->
              <div v-else-if="ocrResults.payment" class="recognition-complete">
                <div class="complete-icon">
                  <el-icon><CheckCircle /></el-icon>
                </div>
                <div class="complete-text">识别完成</div>
                <el-button type="primary" @click="viewDetails('payment')" size="small" class="view-details-btn">
                  <el-icon><Document /></el-icon>
                  查看识别详情
                </el-button>
                <el-button type="info" @click="handlePreview(paymentImg[0], 'payment')" size="small" class="preview-btn">
                  预览图片
                </el-button>
                <el-button type="danger" @click="handleFileRemove(null, [], 'payment')" size="small" class="remove-btn">
                  重新上传
                </el-button>
              </div>
            </div>
          </el-col>

          <!-- 运输发票上传 -->
          <el-col :span="12" :md="6">
            <div class="upload-container">
              <el-upload
                v-model:file-list="transportImg"
                list-type="picture-card"
                :limit="1"
                accept="image/*"
                :auto-upload="false"
                :on-change="(file, fileList) => handleFileChange(fileList, 'transport')"
                :on-remove="(file, fileList) => handleFileRemove(file, fileList, 'transport')"
                :on-preview="(file) => handlePreview(file, 'transport')"
                :on-exceed="(files, fileList) => handleExceed(files, fileList, 'transport')"
                :disabled="isTransportLoading"
                v-if="!ocrResults.transport"
              >
                <div class="upload-icon">
                  <el-icon><Plus /></el-icon>
                  <div>运输发票</div>
                </div>
              </el-upload>
              
              <!-- AI识别中状态 -->
              <div v-if="isTransportLoading" class="ai-loading-container">
                <div class="ai-loading-content">
                  <el-icon class="ai-loading-icon"><Loading /></el-icon>
                  <div class="ai-loading-text">AI大模型正在识别中...</div>
                  <div class="ai-loading-subtext">请稍候，正在分析运输发票信息</div>
                </div>
              </div>
              
              <!-- 识别完成状态 -->
              <div v-else-if="ocrResults.transport" class="recognition-complete">
                <div class="complete-icon">
                  <el-icon><CheckCircle /></el-icon>
                </div>
                <div class="complete-text">识别完成</div>
                <el-button type="primary" @click="viewDetails('transport')" size="small" class="view-details-btn">
                  <el-icon><Document /></el-icon>
                  查看识别详情
                </el-button>
                <el-button type="info" @click="handlePreview(transportImg[0], 'transport')" size="small" class="preview-btn">
                  预览图片
                </el-button>
                <el-button type="danger" @click="handleFileRemove(null, [], 'transport')" size="small" class="remove-btn">
                  重新上传
                </el-button>
              </div>
            </div>
          </el-col>
        </el-row>

        <!-- 检测结果区域 -->
        <div class="result-container" v-if="detectionResult">
          <el-card>
            <template #header>
              <div class="card-header">
                <span>检测结果</span>
              </div>
            </template>
            <div class="result-content">
              <div class="result-status" :class="detectionResult.status === 'normal' ? 'normal' : 'warning'">
                <el-icon :class="detectionResult.status === 'normal' ? 'success-icon' : 'warning-icon'">
                  <CheckCircle v-if="detectionResult.status === 'normal'" />
                  <WarningCircle v-else />
                </el-icon>
                <span>{{ detectionResult.status === 'normal' ? '正常发票' : '疑似虚开发票' }}</span>
                <div class="risk-score" :class="detectionResult.status === 'normal' ? 'low-risk' : 'high-risk'">
                  风险分数: {{ detectionResult.riskScore || 0 }}
                </div>
              </div>
              <div class="result-details">
                <p>{{ detectionResult.details }}</p>
                <div v-if="detectionResult.issues && detectionResult.issues.length > 0" class="issues-list">
                  <h4>检测到的异常项：</h4>
                  <ul>
                    <li v-for="(issue, index) in detectionResult.issues" :key="index" class="issue-item">
                      {{ issue }}
                    </li>
                  </ul>
                </div>
              </div>
            </div>
          </el-card>
        </div>

        <!-- 日志区域 -->
        <el-form class="log-form">
          <el-form-item label="检测日志">
            <el-input
              type="textarea"
              v-model="log"
              :rows="6"
              placeholder="检测日志将在此显示..."
              readonly
            />
          </el-form-item>
        </el-form>

        <!-- 操作按钮 -->
        <div class="btn-group">
          <el-tooltip :disabled="canDetect" content="需上传全部图片并完成识别才可以开始检测" placement="top">
            <el-button type="primary" @click="handleDetect" :disabled="!canDetect">虚开检测</el-button>
          </el-tooltip>
          <el-button type="success" @click="handleRedetect">重新检测</el-button>
        </div>
      </div>
    </main>

    <!-- 图片预览对话框 -->
    <el-dialog
      v-model="imageDialogVisible"
      title="图片预览"
      width="80%"
      :before-close="() => imageDialogVisible = false"
    >
      <div class="image-preview">
        <el-image
          :src="currentImageUrl"
          fit="contain"
          :preview-src-list="[currentImageUrl]"
        />
      </div>
    </el-dialog>

    <!-- OCR详情对话框 -->
    <el-dialog
      v-model="dialogVisible"
      :title="currentTitle + ' - AI大模型识别结果'"
      width="60%"
      :before-close="() => dialogVisible = false"
    >
      <div class="ocr-content">
        <pre>{{ currentOcrContent }}</pre>
      </div>
      <template #footer>
        <span class="dialog-footer">
          <el-button @click="dialogVisible = false">关闭</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script setup>
import { ref, computed, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { 
  Plus, 
  Document, 
  CircleCheck as CheckCircle, 
  WarningFilled as WarningCircle,
  Loading
} from '@element-plus/icons-vue'
import { getInvoiceInfo, getContractInfo, getPaymentInfo, getTransportInfo } from '@/utils/aiUtil'


// 图片文件列表
const invoiceImg = ref([])
const contractImg = ref([])
const paymentImg = ref([])
const transportImg = ref([])

// 日志内容
const log = ref('欢迎使用虚开增值税发票检测系统，请上传相关图片后开始检测。')

// OCR识别结果
const ocrResults = ref({
  invoice: '',
  contract: '',
  payment: '',
  transport: ''
})

// 原始OCR数据存储（用于检测逻辑）
const rawOcrData = ref({
  invoice: null,
  contract: null,
  payment: null,
  transport: null
})

// 识别loading状态
const isInvoiceLoading = ref(false)
const isContractLoading = ref(false)
const isPaymentLoading = ref(false)
const isTransportLoading = ref(false)

// 检测结果
const detectionResult = ref(null)

// 对话框控制
const dialogVisible = ref(false)
const imageDialogVisible = ref(false)
const currentOcrContent = ref('')
const currentTitle = ref('')
const currentImageUrl = ref('')

// 检测状态控制
const canDetect = computed(() => {
  // 检查是否所有图片都已上传且识别完成，并且没有正在进行的识别
  return invoiceImg.value.length > 0 && 
         contractImg.value.length > 0 && 
         paymentImg.value.length > 0 && 
         transportImg.value.length > 0 &&
         Object.values(ocrResults.value).every(v => v) &&
         !isInvoiceLoading.value &&
         !isContractLoading.value &&
         !isPaymentLoading.value &&
         !isTransportLoading.value
})

// 处理文件超出限制
const handleExceed = (files, fileList, type) => {
  ElMessage.warning(`每个${getTypeName(type)}只能上传一个文件`);
}

// 检测按钮事件
const handleDetect = () => {
  log.value += '\n[虚开检测] 检测开始...'
  
  // 获取原始数据
  const invoiceData = rawOcrData.value.invoice
  const contractData = rawOcrData.value.contract
  const paymentData = rawOcrData.value.payment
  const transportData = rawOcrData.value.transport
  
  if (!invoiceData || !contractData || !paymentData || !transportData) {
    log.value += '\n[虚开检测] 错误：缺少必要的识别数据'
    return
  }
  
  // 检测结果对象
  const detectionIssues = []
  let riskScore = 0
  
  // 1. 比对发票与合同信息
  log.value += '\n[虚开检测] 正在比对发票与合同信息...'
  
  // 检查购买方信息一致性
  if (invoiceData.buyer_info?.name && contractData.buyer?.name) {
    if (!isSimilarText(invoiceData.buyer_info.name, contractData.buyer.name)) {
      detectionIssues.push('发票购买方名称与合同买方名称不一致')
      riskScore += 20
    }
  }
  
  // 检查销售方信息一致性
  if (invoiceData.seller_info?.name && contractData.seller?.name) {
    if (!isSimilarText(invoiceData.seller_info.name, contractData.seller.name)) {
      detectionIssues.push('发票销售方名称与合同卖方名称不一致')
      riskScore += 20
    }
  }
  
  // 检查金额一致性
  const invoiceAmount = parseFloat(invoiceData.total_amount?.replace(/[^\d.]/g, '') || '0')
  const contractTotalAmount = calculateContractTotalAmount(contractData)
  
  if (contractTotalAmount > 0) {
    const amountDiff = Math.abs(invoiceAmount - contractTotalAmount)
    const amountDiffPercent = (amountDiff / contractTotalAmount) * 100
    
    if (amountDiffPercent > 5) { // 允许5%的误差
      detectionIssues.push(`发票金额(${invoiceAmount})与合同金额(${contractTotalAmount})差异过大(${amountDiffPercent.toFixed(2)}%)`)
      riskScore += 30
    }
  }
  
  // 2. 检查付款记录
  log.value += '\n[虚开检测] 正在核对付款记录...'
  
  const paymentTotalAmount = calculatePaymentTotalAmount(paymentData)
  if (paymentTotalAmount > 0) {
    const paymentDiff = Math.abs(invoiceAmount - paymentTotalAmount)
    const paymentDiffPercent = (paymentDiff / invoiceAmount) * 100
    
    if (paymentDiffPercent > 10) { // 允许10%的误差
      detectionIssues.push(`发票金额(${invoiceAmount})与付款金额(${paymentTotalAmount})差异过大(${paymentDiffPercent.toFixed(2)}%)`)
      riskScore += 25
    }
  }
  
  // 3. 检查运输信息
  log.value += '\n[虚开检测] 正在验证运输信息...'
  
  // 检查运输发票的购买方与主发票是否一致
  if (transportData.buyer_info?.name && invoiceData.buyer_info?.name) {
    if (!isSimilarText(transportData.buyer_info.name, invoiceData.buyer_info.name)) {
      detectionIssues.push('运输发票购买方与主发票购买方不一致')
      riskScore += 15
    }
  }
  
  // 检查运输发票的销售方与主发票是否一致
  if (transportData.seller_info?.name && invoiceData.seller_info?.name) {
    if (!isSimilarText(transportData.seller_info.name, invoiceData.seller_info.name)) {
      detectionIssues.push('运输发票销售方与主发票销售方不一致')
      riskScore += 15
    }
  }
  
  // 4. 检查发票基本信息
  log.value += '\n[虚开检测] 正在验证发票基本信息...'
  
  // 检查发票号码格式
  if (!isValidInvoiceCode(invoiceData.invoice_code)) {
    detectionIssues.push('发票号码格式异常')
    riskScore += 10
  }
  
  // 检查开票日期合理性
  if (!isValidInvoiceDate(invoiceData.invoice_date)) {
    detectionIssues.push('开票日期异常')
    riskScore += 10
  }
  
  // 5. 生成检测结果
  log.value += '\n[虚开检测] 正在生成检测报告...'
  
  const isNormal = riskScore < 30 // 风险分数低于30分为正常
  
  detectionResult.value = {
    status: isNormal ? 'normal' : 'warning',
    details: isNormal 
      ? '发票信息与合同、付款记录、物流信息基本一致，未发现明显异常。'
      : `发现${detectionIssues.length}项异常：\n${detectionIssues.map((issue, index) => `${index + 1}. ${issue}`).join('\n')}`,
    riskScore: riskScore,
    issues: detectionIssues
  }
  
  log.value += `\n[虚开检测] 检测完成: ${isNormal ? '未发现异常' : '发现疑似虚开特征'} (风险分数: ${riskScore})`
}

// 重新检测按钮事件
const handleRedetect = () => {
  log.value += '\n[重新检测] 检测重新开始...'
  detectionResult.value = null
  handleDetect()
}


// 获取类型名称
const getTypeName = (type) => {
  const typeMap = {
    invoice: '发票图片',
    contract: '合同图片',
    payment: '付款单据',
    transport: '运输发票'
  }
  return typeMap[type] || type
}

// 查看OCR详情
const viewDetails = (type) => {
  currentTitle.value = getTypeName(type)
  currentOcrContent.value = ocrResults.value[type]
  dialogVisible.value = true
}

// 图片预览
const handlePreview = (file, type) => {
  if (!file) {
    ElMessage.error('没有找到图片文件');
    return;
  }

  // 确保URL存在且有效
  if (!file.url && file.raw) {
    file.url = URL.createObjectURL(file.raw);
    log.value += `\n[预览修复] 重新创建图片URL: ${type}`;
  }

  if (!file.url) {
    ElMessage.error('图片URL无效，无法预览');
    return;
  }

  // 检查URL是否有效
  const img = new Image();
  let isLoaded = false;

  // 设置超时处理，防止图片加载时间过长
  const timeout = setTimeout(() => {
    if (!isLoaded) {
      ElMessage.error('图片加载超时，请重试');
      img.src = ''; // 取消图片加载
    }
  }, 3000);

  img.onload = () => {
    isLoaded = true;
    clearTimeout(timeout);
    currentImageUrl.value = file.url;
    // 使用nextTick确保DOM更新完成后再显示对话框
    nextTick(() => {
      imageDialogVisible.value = true;
    });
  };

  img.onerror = () => {
    isLoaded = true;
    clearTimeout(timeout);
    ElMessage.error('图片加载失败，正在尝试修复...');
    // 尝试重新创建URL
    if (file.raw) {
      file.url = URL.createObjectURL(file.raw);
      log.value += `\n[预览修复] 重新创建图片URL: ${type}`;
      // 延迟后再次尝试加载
      setTimeout(() => {
        const retryImg = new Image();
        retryImg.onload = () => {
          currentImageUrl.value = file.url;
          nextTick(() => {
            imageDialogVisible.value = true;
          });
        };
        retryImg.onerror = () => {
          ElMessage.error('图片修复失败，请重新上传后再试');
        };
        retryImg.src = file.url;
      }, 500);
    }
  };

  img.src = file.url;
}

// 工具函数：将File对象转换为base64字符串
const convertFileToBase64 = (file) => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    // 读取文件并转换为data URL（base64格式）
    reader.readAsDataURL(file)
    // 读取成功时触发
    reader.onload = () => {
      // result格式为 "..."，只返回逗号后面的部分
      const base64Result = reader.result.split(',')[1]
      resolve(base64Result)
    }
    // 读取失败时触发
    reader.onerror = (error) => {
      reject(new Error(`文件转换失败: ${error.message}`))
    }
  })
}



// 文件上传处理
const handleFileChange = async (fileList, type) => {
  if (fileList.length > 0) {
    const file = fileList[0]
    // 释放旧的URL（如果存在）
    let oldFile;
    if (type === 'invoice' && invoiceImg.value.length > 0) {
      oldFile = invoiceImg.value[0];
    } else if (type === 'contract' && contractImg.value.length > 0) {
      oldFile = contractImg.value[0];
    } else if (type === 'payment' && paymentImg.value.length > 0) {
      oldFile = paymentImg.value[0];
    } else if (type === 'transport' && transportImg.value.length > 0) {
      oldFile = transportImg.value[0];
    }
    if (oldFile && oldFile.url) {
      URL.revokeObjectURL(oldFile.url);
    }
    // 创建图片预览URL
    file.url = URL.createObjectURL(file.raw)
    log.value += `\n[文件上传] ${getTypeName(type)}上传成功: ${file.name}`
    // 先将图片转换为base64
    const base64 = await convertFileToBase64(file.raw)
    if(getTypeName(type) === '发票图片'){
      // 这是发票，调用发票的AI智能识别方法 需要转换 base64
      log.value += `\n[发票识别] AI大模型正在识别发票信息...`
      isInvoiceLoading.value = true
      try {
        const invoiceInfo = await getInvoiceInfo(base64)
        let content = invoiceInfo.choices[0].message.content
        // 去掉前后的```json和```
        content = content.replace(/^```json\s*|\s*```$/g, '')
        // 转换为JSON对象
        const invoiceData = JSON.parse(content)
        // 格式化输出为用户友好的文本
        let formattedInvoice = '';
        formattedInvoice += `发票类型：${invoiceData.invoice_type}\n`;
        formattedInvoice += `发票号码：${invoiceData.invoice_code}\n`;
        formattedInvoice += `开票日期：${invoiceData.invoice_date}\n`;
        formattedInvoice += `页数：${invoiceData.total_pages}\n\n`;
        formattedInvoice += `购买方信息：\n`;
        formattedInvoice += `  名称：${invoiceData.buyer_info.name}\n`;
        formattedInvoice += `  统一社会信用代码：${invoiceData.buyer_info.tax_id}\n\n`;
        formattedInvoice += `销售方信息：\n`;
        formattedInvoice += `  名称：${invoiceData.seller_info.name}\n`;
        formattedInvoice += `  统一社会信用代码：${invoiceData.seller_info.tax_id}\n\n`;
        formattedInvoice += `商品明细：\n`;
        invoiceData.items.forEach((item, index) => {
          formattedInvoice += `  ${index + 1}. 商品名称：${item.item_name}\n`;
          formattedInvoice += `     规格型号：${item.specification}\n`;
          formattedInvoice += `     单位：${item.unit}\n`;
          formattedInvoice += `     数量：${item.quantity}\n`;
          formattedInvoice += `     单价：${item.unit_price}\n`;
          formattedInvoice += `     金额：${item.amount}\n`;
          formattedInvoice += `     税率：${item.tax_rate}\n`;
          formattedInvoice += `     税额：${item.tax_amount}\n\n`;
        });
        formattedInvoice += `不含税金额：${invoiceData.total_amount}\n`;
        formattedInvoice += `税额：${invoiceData.total_tax_amount}\n`;
        formattedInvoice += `含税金额（小写）：${invoiceData.total_including_tax}\n`;
        formattedInvoice += `含税金额（大写）：${invoiceData.total_in_words}\n`;
        formattedInvoice += `备注：${invoiceData.remark}\n`;
        formattedInvoice += `开票人：${invoiceData.issuer}\n`;
        // 存储格式化后的文本
        ocrResults.value.invoice = formattedInvoice;
        rawOcrData.value.invoice = invoiceData; // 存储原始数据
        log.value += `\n[发票识别] 发票信息识别完成`
      } catch (error) {
        log.value += `\n[发票识别] 识别失败: ${error.message}`
      } finally {
        isInvoiceLoading.value = false
      }
    } else if(getTypeName(type) === '合同图片'){
      // 这是合同，调用合同的AI智能识别方法
      log.value += `\n[合同识别] AI大模型正在识别合同信息...`;
      isContractLoading.value = true;
      try {
        const contractInfo = await getContractInfo(base64);
        let content = contractInfo.choices[0].message.content;
        // 去掉前后的```json和```
        content = content.replace(/^```json\s*|\s*```$/g, '');
        // 转换为JSON对象
        const contractData = JSON.parse(content);
        // 格式化输出为用户友好的文本
        let formattedContract = '';
        formattedContract += `合同标题：${contractData.contract_title}\n`;
        formattedContract += `合同编号：${contractData.contract_number}\n\n`;
        formattedContract += `买方信息：\n`;
        formattedContract += `  名称：${contractData.buyer?.name || '无'}\n`;
        formattedContract += `  注册地址：${contractData.buyer?.registered_address || '无'}\n\n`;
        formattedContract += `卖方信息：\n`;
        formattedContract += `  名称：${contractData.seller?.name || '无'}\n`;
        formattedContract += `  注册地址：${contractData.seller?.registered_address || '无'}\n\n`;
        formattedContract += `鉴于条款：\n`;
        contractData.consideration?.forEach((item, index) => {
          formattedContract += `  ${index + 1}. ${item.content || '无'}\n`;
        });
        formattedContract += `\n协议概述：${contractData.agreement || '无'}\n\n`;
        formattedContract += `产品明细：\n`;
        contractData.products?.forEach((item, index) => {
          formattedContract += `  ${index + 1}. 商品名称：${item.short_name || '无'}\n`;
          formattedContract += `     项目编号：${item.item_number || '无'}\n`;
          formattedContract += `     材料编号：${item.material_number || '无'}\n`;
          formattedContract += `     数量：${item.quantity || '无'}\n`;
          formattedContract += `     单位：${item.unit || '无'}\n`;
          formattedContract += `     不含税单价：${item.unit_price_ex_tax || '无'}\n`;
          formattedContract += `     含税单价：${item.unit_price_including_tax || '无'}\n`;
          formattedContract += `     货币：${item.currency || '无'}\n`;
          formattedContract += `     税率：${item.tax_rate || '无'}\n\n`;
        });
        formattedContract += `项目备注：${contractData.item_notes || '无'}\n`;
        // 存储格式化后的文本
        ocrResults.value.contract = formattedContract;
        rawOcrData.value.contract = contractData; // 存储原始数据
        log.value += `\n[合同识别] 合同信息识别完成`;
      } catch (error) {
        log.value += `\n[合同识别] 识别失败: ${error.message}`;
      } finally {
        isContractLoading.value = false;
      }
    }else if(getTypeName(type) === '付款单据'){
      // 这是付款单据，调用付款单据的AI智能识别方法
      log.value += `\n[付款单据识别] AI大模型正在识别付款单据信息...`;
      isPaymentLoading.value = true;
      try {
        const paymentInfo = await getPaymentInfo(base64);
        let content = paymentInfo.choices[0].message.content;
        // 去掉前后的```json和```
        content = content.replace(/^```json\s*|\s*```$/g, '');
        // 转换为JSON对象
        const paymentData = JSON.parse(content);
        // 格式化输出为用户友好的文本
        let formattedPayment = '';
        formattedPayment += `单据标题：${paymentData.document_title || '无'}\n\n`;
        formattedPayment += `基本信息：\n`;
        formattedPayment += `  付款方式：${paymentData.basic_info?.payment_method || '无'}\n`;
        formattedPayment += `  期望付款日期：${paymentData.basic_info?.expected_payment_date || '无'}\n\n`;
        formattedPayment += `收款方账户信息：\n`;
        paymentData.payee_account_details?.forEach((item, index) => {
          formattedPayment += `  ${index + 1}. 供应商名称：${item.supplier_name || '无'}\n`;
          formattedPayment += `     供应商编码：${item.supplier_code || '无'}\n`;
          formattedPayment += `     开户行：${item.opening_bank || '无'}\n`;
          formattedPayment += `     联行号：${item.bank_branch_code || '无'}\n`;
          formattedPayment += `     账户名：${item.account_name || '无'}\n`;
          formattedPayment += `     账号：${item.account_number || '无'}\n`;
          formattedPayment += `     金额：${item.amount || '无'}\n\n`;
        });
        formattedPayment += `未清预付明细：${paymentData.unpaid_advance_details || '无'}\n`;
        formattedPayment += `采购运费：${paymentData.purchase_freight || '无'}\n\n`;
        formattedPayment += `销售运费：\n`;
        paymentData.sales_freight?.forEach((item, index) => {
          formattedPayment += `  ${index + 1}. 发生日期：${item.occurrence_date || '无'}\n`;
          formattedPayment += `     费用大类：${item.expense_category || '无'}\n`;
          formattedPayment += `     费用小类：${item.expense_subcategory || '无'}\n`;
          formattedPayment += `     摘要：${item.description || '无'}\n`;
          formattedPayment += `     含税金额：${item.tax_inclusive_amount || '无'}\n`;
          formattedPayment += `     不含税金额：${item.tax_exclusive_amount || '无'}\n\n`;
        });
        // 存储格式化后的文本
        ocrResults.value.payment = formattedPayment;
        rawOcrData.value.payment = paymentData; // 存储原始数据
        log.value += `\n[付款单据识别] 付款单据信息识别完成`;
      } catch (error) {
        log.value += `\n[付款单据识别] 识别失败: ${error.message}`;
      } finally {
        isPaymentLoading.value = false;
      }
    }else if(getTypeName(type) === '运输发票'){
      // 这是运输发票，调用运输发票的AI智能识别方法
      log.value += `\n[运输发票识别] AI大模型正在识别运输发票信息...`;
      isTransportLoading.value = true;
      try {
        const transportInfo = await getTransportInfo(base64);
        let content = transportInfo.choices[0].message.content;
        // 去掉前后的```json和```
        content = content.replace(/^```json\s*|\s*```$/g, '');
        // 转换为JSON对象
        const transportData = JSON.parse(content);
        // 格式化输出为用户友好的文本
        let formattedTransport = '';
        formattedTransport += `发票标题：${transportData.invoice_title || '无'}\n`;
        formattedTransport += `服务类型：${transportData.service_type || '无'}\n`;
        formattedTransport += `发票号码：${transportData.invoice_number || '无'}\n`;
        formattedTransport += `开票日期：${transportData.invoice_date || '无'}\n\n`;
        formattedTransport += `购买方信息：\n`;
        formattedTransport += `  名称：${transportData.buyer_info?.name || '无'}\n`;
        formattedTransport += `  统一社会信用代码：${transportData.buyer_info?.tax_id || '无'}\n\n`;
        formattedTransport += `销售方信息：\n`;
        formattedTransport += `  名称：${transportData.seller_info?.name || '无'}\n`;
        formattedTransport += `  统一社会信用代码：${transportData.seller_info?.tax_id || '无'}\n\n`;
        formattedTransport += `商品明细：\n`;
        transportData.items?.forEach((item, index) => {
          formattedTransport += `  ${index + 1}. 项目名称：${item.item_name || '无'}\n`;
          formattedTransport += `     单价：${item.unit_price || '无'}\n`;
          formattedTransport += `     金额：${item.amount || '无'}\n`;
          formattedTransport += `     税率：${item.tax_rate || '无'}\n`;
          formattedTransport += `     税额：${item.tax_amount || '无'}\n\n`;
        });
        formattedTransport += `不含税金额：${transportData.total_amount || '无'}\n`;
        formattedTransport += `税额：${transportData.total_tax_amount || '无'}\n`;
        formattedTransport += `含税金额（小写）：${transportData.total_including_tax || '无'}\n`;
        formattedTransport += `含税金额（大写）：${transportData.total_in_words || '无'}\n\n`;
        formattedTransport += `运输详情：\n`;
        formattedTransport += `  运输工具种类：${transportData.transport_details?.transport_tool_type || '无'}\n`;
        formattedTransport += `  运输工具牌号：${transportData.transport_details?.transport_tool_license_plate || '无'}\n`;
        formattedTransport += `  起运地：${transportData.transport_details?.origin || '无'}\n`;
        formattedTransport += `  到达地：${transportData.transport_details?.destination || '无'}\n`;
        formattedTransport += `  运输货物名称：${transportData.transport_details?.cargo_name || '无'}\n\n`;
        formattedTransport += `备注信息：\n`;
        formattedTransport += `  开票人：${transportData.issuer || '无'}\n`;
        // 存储格式化后的文本
        ocrResults.value.transport = formattedTransport;
        rawOcrData.value.transport = transportData; // 存储原始数据
        log.value += `\n[运输发票识别] 运输发票信息识别完成`;
      } catch (error) {
        log.value += `\n[运输发票识别] 识别失败: ${error.message}`;
      } finally {
        isTransportLoading.value = false;
      }
      }
  }
}

// 文件移除处理
const handleFileRemove = (file, fileList, type) => {
  // 释放URL对象
  if (file && file.url) {
    URL.revokeObjectURL(file.url)
  }
  
  // 清空对应的文件列表
  if (type === 'invoice') {
    invoiceImg.value = []
  } else if (type === 'contract') {
    contractImg.value = []
  } else if (type === 'payment') {
    paymentImg.value = []
  } else if (type === 'transport') {
    transportImg.value = []
  }
  
  log.value += `\n[文件移除] ${getTypeName(type)}已移除`
  ocrResults.value[type] = ''
  rawOcrData.value[type] = null // 移除原始数据
  detectionResult.value = null
}

// 辅助函数：文本相似度比较
const isSimilarText = (text1, text2) => {
  if (!text1 || !text2) return false
  
  const clean1 = text1.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, '').toLowerCase()
  const clean2 = text2.replace(/[^\u4e00-\u9fa5a-zA-Z0-9]/g, '').toLowerCase()
  
  // 简单的包含关系判断
  return clean1.includes(clean2) || clean2.includes(clean1) || 
         clean1 === clean2 || 
         calculateSimilarity(clean1, clean2) > 0.8
}

// 计算文本相似度
const calculateSimilarity = (str1, str2) => {
  if (str1 === str2) return 1
  if (str1.length === 0 || str2.length === 0) return 0
  
  const longer = str1.length > str2.length ? str1 : str2
  const shorter = str1.length > str2.length ? str2 : str1
  
  if (longer.length === 0) return 1
  
  return (longer.length - editDistance(longer, shorter)) / longer.length
}

// 编辑距离算法
const editDistance = (str1, str2) => {
  const matrix = []
  
  for (let i = 0; i <= str2.length; i++) {
    matrix[i] = [i]
  }
  
  for (let j = 0; j <= str1.length; j++) {
    matrix[0][j] = j
  }
  
  for (let i = 1; i <= str2.length; i++) {
    for (let j = 1; j <= str1.length; j++) {
      if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
        matrix[i][j] = matrix[i - 1][j - 1]
      } else {
        matrix[i][j] = Math.min(
          matrix[i - 1][j - 1] + 1,
          matrix[i][j - 1] + 1,
          matrix[i - 1][j] + 1
        )
      }
    }
  }
  
  return matrix[str2.length][str1.length]
}

// 计算合同总金额
const calculateContractTotalAmount = (contractData) => {
  if (!contractData.products || !Array.isArray(contractData.products)) return 0
  
  return contractData.products.reduce((total, product) => {
    const quantity = parseFloat(product.quantity?.replace(/[^\d.]/g, '') || '0')
    const unitPrice = parseFloat(product.unit_price_ex_tax?.replace(/[^\d.]/g, '') || '0')
    return total + (quantity * unitPrice)
  }, 0)
}

// 计算付款总金额
const calculatePaymentTotalAmount = (paymentData) => {
  if (!paymentData.payee_account_details || !Array.isArray(paymentData.payee_account_details)) return 0
  
  return paymentData.payee_account_details.reduce((total, item) => {
    const amount = parseFloat(item.amount?.replace(/[^\d.]/g, '') || '0')
    return total + amount
  }, 0)
}

// 验证发票号码格式
const isValidInvoiceCode = (code) => {
  if (!code) return false
  // 发票号码通常是8位数字
  return /^\d{8}$/.test(code.replace(/\s/g, ''))
}

// 验证开票日期合理性
const isValidInvoiceDate = (dateStr) => {
  if (!dateStr) return false
  
  const date = new Date(dateStr)
  const now = new Date()
  const oneYearAgo = new Date(now.getFullYear() - 1, now.getMonth(), now.getDate())
  
  // 检查日期是否在合理范围内（过去一年内）
  return date >= oneYearAgo && date <= now
}
</script>

<style scoped>
.app-container {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background-color: #f5f7fa;
}

header {
  text-align: center;
  padding: 20px 0;
  background-color: #fff;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
  margin-bottom: 30px;
}

.main-title {
  font-size: 2rem;
  font-weight: bold;
  color: #409EFF;
  letter-spacing: 2px;
  margin: 0;
}

.content {
  flex: 1;
  display: flex;
  justify-content: center;
  padding: 0 20px 30px;
}

.container {
  max-width: 1200px;
  width: 100%;
  padding: 24px;
  background: #fff;
  border-radius: 12px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.08);
}

.upload-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 16px;
  border-radius: 8px;
  transition: all 0.3s;
  position: relative;
}

.upload-container:hover {
  background-color: #f5f7fa;
}

.upload-icon {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.upload-icon .el-icon {
  font-size: 24px;
  margin-bottom: 8px;
}

.detail-link {
  margin-top: 12px;
  text-align: center;
  width: 100%;
}

.log-form {
  margin-top: 24px;
}

.btn-group {
  display: flex;
  justify-content: flex-end;
  gap: 16px;
  margin-top: 16px;
  padding: 16px 0;
  border-top: 1px solid #eee;
}

.result-container {
  margin: 24px 0;
  animation: fadeIn 0.5s;
}

@keyframes fadeIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

.result-status {
  display: flex;
  align-items: center;
  margin-bottom: 16px;
  font-size: 18px;
  font-weight: 500;
  gap: 12px;
}

.result-status .el-icon {
  margin-right: 8px;
  font-size: 24px;
}

.risk-score {
  padding: 4px 8px;
  border-radius: 4px;
  font-size: 14px;
  font-weight: 600;
}

.low-risk {
  background-color: #f0f9ff;
  color: #67C23A;
  border: 1px solid #67C23A;
}

.high-risk {
  background-color: #fef0f0;
  color: #F56C6C;
  border: 1px solid #F56C6C;
}

.normal .success-icon {
  color: #67C23A;
}

.normal span {
  color: #67C23A;
}

.warning .warning-icon {
  color: #E6A23C;
}

.warning span {
  color: #E6A23C;
}

.result-details {
  padding: 12px;
  background-color: #f5f7fa;
  border-radius: 6px;
  line-height: 1.6;
}

.issues-list {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid #e4e7ed;
}

.issues-list h4 {
  margin: 0 0 12px 0;
  color: #F56C6C;
  font-size: 16px;
}

.issues-list ul {
  margin: 0;
  padding-left: 20px;
}

.issue-item {
  margin-bottom: 8px;
  color: #606266;
  line-height: 1.5;
}

.ocr-content {
  background: #f5f5f5;
  padding: 16px;
  border-radius: 8px;
  max-height: 400px;
  overflow-y: auto;
  white-space: pre-wrap;
}

.ocr-content pre {
  margin: 0;
  white-space: pre-wrap;
  word-wrap: break-word;
  font-family: 'Courier New', monospace;
  font-size: 14px;
  line-height: 1.5;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
}

.image-preview {
  width: 100%;
  text-align: center;
  padding: 16px 0;
}

.image-preview .el-image {
  max-height: 600px;
  margin: 0 auto;
}

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.ai-loading-container {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20px;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  border-radius: 8px;
  margin-top: 12px;
  width: 100%;
  border: 2px dashed #409EFF;
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.1);
}

.ai-loading-content {
  text-align: center;
}

.ai-loading-icon {
  font-size: 48px;
  color: #409EFF;
  margin-bottom: 10px;
  animation: rotate 2s linear infinite;
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.ai-loading-text {
  font-size: 18px;
  font-weight: bold;
  color: #409EFF;
  margin-bottom: 5px;
}

.ai-loading-subtext {
  font-size: 14px;
  color: #606266;
}

.recognition-complete {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
  background: linear-gradient(135deg, #f0f9eb 0%, #e1f3d8 100%);
  border-radius: 8px;
  margin-top: 12px;
  width: 100%;
  border: 2px solid #67c23a;
  box-shadow: 0 4px 12px rgba(103, 194, 58, 0.1);
}

.complete-icon {
  font-size: 60px;
  color: #67c23a;
  margin-bottom: 15px;
  animation: bounce 0.6s ease-in-out;
}

@keyframes bounce {
  0%, 20%, 50%, 80%, 100% {
    transform: translateY(0);
  }
  40% {
    transform: translateY(-10px);
  }
  60% {
    transform: translateY(-5px);
  }
}

.complete-text {
  font-size: 20px;
  font-weight: bold;
  color: #67c23a;
  margin-bottom: 15px;
}

.view-details-btn {
  margin-bottom: 10px;
  transition: all 0.3s ease;
}

.view-details-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(64, 158, 255, 0.3);
}

.preview-btn {
  background-color: #409eff;
  border-color: #409eff;
  margin-bottom: 10px;
  margin-left: 10px;
  transition: all 0.3s ease;
}

.preview-btn:hover {
  background-color: #66b1ff;
  border-color: #66b1ff;
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(64, 158, 255, 0.3);
}

.remove-btn {
  background-color: #f56c6c;
  border-color: #f56c6c;
  transition: all 0.3s ease;
}

.remove-btn:hover {
  background-color: #f78989;
  border-color: #f78989;
  transform: translateY(-2px);
  box-shadow: 0 4px 8px rgba(245, 108, 108, 0.3);
}
</style>
